package jp.co.nes.awssupport.business.logic;

import java.time.YearMonth;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.amazonaws.regions.Regions;

import jp.co.nes.awssupport.access.dao.ReservedManageDao;
import jp.co.nes.awssupport.business.bean.BillingCsvBean;
import jp.co.nes.awssupport.business.bean.ReservedInputBean;
import jp.co.nes.awssupport.business.bean.ReservedResultBean;
import jp.co.nes.awssupport.business.utility.BillingCsvUtil;
import jp.co.nes.awssupport.business.utility.ReservedHelper;
import jp.co.nes.awssupport.common.base.CommonException;
import jp.co.nes.awssupport.common.bean.AwsKeyBean;
import jp.co.nes.awssupport.common.bean.ContractInformationBean;
import jp.co.nes.awssupport.common.bean.ReservedManageBean;
import jp.co.nes.awssupport.common.utility.DateUtil;

/**
 * リザーブド管理処理です。
 */
public class ReservedManageProcessing {

    /** DescribeReservedヘルパー */
    private ReservedHelper helper;

    /** 処理対象年月 */
    private YearMonth targetYearMonth;

    /** 契約情報管理 */
    private ContractInformationManage ciManage;

    /**
     * 処理対象年月、DescribeReservedヘルパーを引数にもつコンストラクタです。
     *
     * @param targetYearMonth 処理対象年月
     * @param helper DescribeReservedヘルパー
     */
    public ReservedManageProcessing(YearMonth targetYearMonth, ReservedHelper helper) {
        this.helper = helper;
        this.targetYearMonth = targetYearMonth;
        ciManage = new ContractInformationManage(targetYearMonth);
    }

    /**
     * リザーブド管理を保存します。<br>
     * 請求CSVリストは、リザーブド管理に保存する請求CSVを設定したリストです。
     *
     * @param csvList 請求CSVリスト
     * @param max バッチ更新の最大数
     */
    public void save(List<BillingCsvBean> csvList, int max) {
        ReservedManageDao dao = new ReservedManageDao();
        dao.delete(targetYearMonth);

        List<ReservedManageBean> insertList = new ArrayList<>();
        for (BillingCsvBean csvBean : csvList) {
            String linkedAccount = csvBean.getLinkedAccountId();
            ContractInformationBean ciBean = ciManage.get(linkedAccount);
            if (ciBean == null) {
                throw new CommonException("contract information not exist(linkedAccount=" + linkedAccount + ")");
            }

            ReservedResultBean rrBean = getReservedResultBean(csvBean, ciBean);
            if (rrBean != null) {
                insertList.add(toReservedManageBean(csvBean, rrBean));
            }
        }
        dao.insert(insertList, max);
    }

    /**
     * ReservedResultを返却します。
     *
     * @param csvBean 請求CSV
     * @param ciBean 契約情報
     * @return DescribeReservedResult
     */
    private ReservedResultBean getReservedResultBean(BillingCsvBean csvBean, ContractInformationBean ciBean) {
        String productName = csvBean.getProductName();
        String reservationARN = csvBean.getReservationARN();
        String id = BillingCsvUtil.getIdFromReservationARN(productName, reservationARN);
        if (StringUtils.isEmpty(id)) {
            StringBuilder builder = new StringBuilder();
            builder.append("id is null or empty(linkedAccountId=");
            builder.append(csvBean.getLinkedAccountId());
            builder.append(",productName=");
            builder.append(productName);
            builder.append(",usageType=");
            builder.append(csvBean.getUsageType());
            builder.append(",reservationARN=");
            builder.append(reservationARN);
            builder.append(")");
            throw new CommonException(builder.toString());
        }

        ReservedManageDao dao = new ReservedManageDao();
        ReservedManageBean rmBean = dao.get(id);
        if (rmBean != null) {
            // 該当するリザーブド管理が存在した場合、処理を抜ける。
            return null;
        }

        Regions regions = BillingCsvUtil.getRegionsFromReservationARN(reservationARN);
        if (regions == null) {
            StringBuilder builder = new StringBuilder();
            builder.append("regions is null(linkedAccountId=");
            builder.append(csvBean.getLinkedAccountId());
            builder.append(",productName=");
            builder.append(productName);
            builder.append(",usageType=");
            builder.append(csvBean.getUsageType());
            builder.append(",reservationARN=");
            builder.append(reservationARN);
            builder.append(")");
            throw new CommonException(builder.toString());
        }

        ReservedInputBean input = new ReservedInputBean();
        input.setRegions(regions);
        input.setId(id);
        input.setProductName(productName);
        input.setUsageQuantity(csvBean.getUsageQuantity());
        input.setUsageStartDate(csvBean.getUsageStartDate());
        input.setUsageEndDate(csvBean.getUsageEndDate());
        input.setAwsKeyBean(getAwsKeyBean(ciBean));
        ReservedResultBean rrBean = helper.getReservedResultBean(input);
        if (rrBean == null) {
            StringBuilder builder = new StringBuilder();
            builder.append("aws api reserved result is null(id=");
            builder.append(id);
            builder.append(",productName=");
            builder.append(productName);
            builder.append(")");
            throw new CommonException(builder.toString());
        }
        return rrBean;
    }

    /**
     * 契約情報からアクセスキー、シークレットキーを取得して、AwsKeyを返却します。
     *
     * @param ciBean 契約情報
     * @return AwsKey
     */
    protected AwsKeyBean getAwsKeyBean(ContractInformationBean ciBean) {
        return ContractInformationManage.getAwsKey(ciBean);
    }

    /**
     * リザーブド管理を返却します。
     *
     * @param csvBean 請求CSV
     * @param rrBean ReservedResultBean
     * @return リザーブド管理
     */
    private ReservedManageBean toReservedManageBean(BillingCsvBean csvBean, ReservedResultBean rrBean) {
        ReservedManageBean rmBean = new ReservedManageBean();
        rmBean.setReservedInstanceId(rrBean.getId());
        rmBean.setSubscriptionId(null); // CUR版はnullで良い。
        rmBean.setPricingPlanId(null);  // CUR版はnullで良い。
        rmBean.setLinkedAccountId(csvBean.getLinkedAccountId());
        rmBean.setProductName(csvBean.getProductName());
        rmBean.setRegionCode(rrBean.getRegionCode());
        rmBean.setMultiAZ(rrBean.getMultiAZ());
        rmBean.setProductDescription(rrBean.getProductDescription());
        rmBean.setInstanceType(rrBean.getType());
        rmBean.setUsageStartDate(rrBean.getStart());
        rmBean.setUsageEndDate(rrBean.getEnd());
        rmBean.setOfferingType(rrBean.getOfferingType());
        rmBean.setOfferingClass(rrBean.getOfferingClass());
        rmBean.setDuration(rrBean.getDuration());
        rmBean.setQuantity(rrBean.getCount());
        rmBean.setReservationARN(csvBean.getReservationARN());
        rmBean.setYearMonth(DateUtil.toInt(targetYearMonth));
        return rmBean;
    }
}
